Skip to content

feat: add offline support with data caching, connectivity monitoring,… - #1138

Merged
mikewheeleer merged 4 commits into
Talenttrust:mainfrom
Oluwasuyi-Oluwatimilehin-Daniel:feature/offline-read-mode
Aug 30, 2026
Merged

feat: add offline support with data caching, connectivity monitoring,…#1138
mikewheeleer merged 4 commits into
Talenttrust:mainfrom
Oluwasuyi-Oluwatimilehin-Daniel:feature/offline-read-mode

Conversation

@Oluwasuyi-Oluwatimilehin-Daniel

Copy link
Copy Markdown
Contributor

Description

Adds an offline-aware read mode for previously loaded contracts on the contract detail page (/contracts/[id]). Temporary connectivity loss no longer erases loaded contract data or leaves the page in an unusable blank state.

Key capabilities introduced:

  • Bounded & Versioned Storage Snapshot: Caches contract read models in localStorage up to a bounded 50 entries (MAX_CACHE_ENTRIES = 50) using chronological LRU eviction, schemaVersion: 1, and staleness detection (5-minute threshold).
  • Corruption Resilience & SSR Safety: Detects and recovers from invalid schema or corrupt JSON in storage without crashing; guards all browser API calls with isBrowser().
  • Dynamic Online/Offline Detection: useOnlineStatus hook tracks browser network changes in real time via window online/offline events.
  • Accessible Warning Banner: OfflineIndicator displays offline and stale state notices with relative cached timestamps ("Cached 5 minutes ago") with role="status" and aria-live="polite".
  • Mutation Disabling: Strictly disables unsafe write actions (Submit Milestone, Release Funds, Dispute, inline milestone edits) when offline or viewing stale snapshots, with clear tooltips and error toasts.
  • Automatic Re-sync: Seamlessly fetches fresh contract data from the upstream resolver/repository and updates the cache when the network connection returns.

Closes #1131

Type of Change

  • Bug fix (non-breaking change that resolves an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Refactor (no functional change, internal code improvement)
  • Documentation update

Pre-flight Checklist

All items must be checked before requesting review.

  • npm run lint passes with no errors
  • npm test passes with no failures
  • npm run build completes successfully

Testing & Coverage

  • Module test coverage for impacted files meets or exceeds the 95% minimum threshold
    (run npm test -- --coverage and check the per-file table)
  • If this PR adds or modifies UI components, accessibility tests were written using
    the shared utilities in src/test-utils/a11y.tsx

What was tested?

  • contractCache.test.ts (14 unit tests):
    • Cache snapshot saving, retrieval, and updating.
    • Staleness evaluation before and after 5-minute threshold.
    • Bounded storage LRU eviction when exceeding 50 entries.
    • Corruption resilience (non-JSON string, malformed schema, corrupted entries).
    • Quota exceeded and storage removal error handling.
  • useOnlineStatus.test.ts (6 unit tests):
    • Initialization from navigator.onLine (including undefined fallback).
    • Real-time reactivity on window offline and online events.
    • Clean event listener teardown on unmount.
  • OfflineIndicator.test.tsx (9 component & a11y tests):
    • Hidden when online with fresh data; rendered when offline or stale.
    • Relative timestamp formatting ("just now", "10 minutes ago", "2 hours ago", "3 days ago").
    • jest-axe automated accessibility audits with 0 violations.
  • ActionPanel.test.tsx (41 unit & a11y tests):
    • Verified disableMutations prop disables submit, release, and dispute actions with informative tooltip titles while keeping View Summary accessible.
    • assertNoA11yViolations checks in normal, open dispute form, and mutation-disabled states.
  • offlineReadMode.test.tsx & page.test.tsx (52 integration tests):
    • Offline on first load: Uncached contract displays clean offline error state and disables mutations.
    • Offline after data loaded: Cached contract displays snapshot with offline indicator and disables unsafe mutations and milestone edits.
    • Stale snapshot: Stale data banner displayed, milestone edits and status changes blocked.
    • Cache corrupt: Malformed localStorage parsed safely without unhandled errors.
    • Connection returns: online event triggers automatic fresh data re-fetch, clears offline banner, and re-enables mutations.
  • Full Suite: All 150 test suites passed (3,076 tests).

Accessibility & Security Notes

Accessibility

  • Ran automated jest-axe accessibility scans and assertNoA11yViolations against OfflineIndicator and ActionPanel in all states (0 violations).
  • OfflineIndicator uses role="status", aria-live="polite", and aria-label to announce network state changes cleanly without disrupting screen reader focus.
  • Action buttons have descriptive title and aria-describedby tooltips explaining why mutations are disabled when offline or viewing stale snapshots.

Security

  • Boundaries & Isolation: Cache only stores public contract read models (ContractData). Wallet private keys, secrets, session authentication tokens, and tenant boundaries are never stored in localStorage.
  • No Offline Writes: Write operations are blocked at the component and handler level when offline or stale to prevent data inconsistency or replay conflicts.
  • Sanitized Presentation: User-supplied strings continue to use safe boundaries and standard React DOM escaping.

@drips-wave

drips-wave Bot commented Aug 29, 2026

Copy link
Copy Markdown

@Oluwasuyi-Oluwatimilehin-Daniel Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@mikewheeleer
mikewheeleer merged commit 0e1adf1 into Talenttrust:main Aug 30, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add offline read mode for previously loaded contracts

2 participants